
#ifndef __SSH_CLIENT_H
#define __SSH_CLIENT_H

#include <libssh2.h>
#include "TCPClient.h"
#include "../db/KeyDB.h"
#include "../crypt/RSAKeyPair.h"

// Ugliest things in the universe++
typedef void (*ssh2_i_functor)(const char *, int, const char *, int, int, const LIBSSH2_USERAUTH_KBDINT_PROMPT *, LIBSSH2_USERAUTH_KBDINT_RESPONSE *, void **);
typedef int (*ssh2_k_functor)(LIBSSH2_SESSION *, unsigned char **, size_t *, const unsigned char *, size_t, void **);

class SSHClient : public TCPClient
{
   public:
      SSHClient(const char *ihostname, int iportno, apr_pool_t *imp) : TCPClient(ihostname, iportno, imp)
      {
         our_username = NULL;
         our_keyname = NULL;
         our_pubkey = NULL;
         our_prvkey = NULL;
         our_pass = NULL;
         tsession = NULL;
         tchannel = NULL;
         delete clientbb;
         clientbb = NULL;
      }
      ~SSHClient();
      static void *KeyboardInteractiveHandler(const char *name, int name_len,
                         const char *instruction, int instruction_len,
                         int num_prompts,
                         const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
                         LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
                         void **abstract);
      virtual ssh2_i_functor GetKeyboardInteractiveHandlerFunction() const { return (ssh2_i_functor)(&KeyboardInteractiveHandler); }
      static int PublicKeyHandler(LIBSSH2_SESSION *session,
                                  unsigned char **sig,
                                  size_t *sig_len,
                                  const unsigned char *data,
                                  size_t data_len,
                                  void **abstract);
      virtual ssh2_k_functor GetPublicKeyHandlerFunction() const { return (ssh2_k_functor)(&PublicKeyHandler); }
      void SetAuthenticatorKeys(KeyDB *sshkeys, const char *keyname, const char *keypass);
      void SetAuthenticatorPassword(const char *authpass);
      const char *DoHandshakeAndGetHostFingerprintInHex();
      const char *DoHandshakeAndGetHostFingerprint();
      int ForcePasswordAuthentication(const char *username);
      int ForceKeyAuthentication(const char *username);
      int SendUsernameAndDoAuthentication(const char *username);
      int SendUsernameAndDoAuthentication(const char *username, int authflags);
      int OpenTunnelChannel(const char *remote_host, int remote_port, int local_port);
      static void TrimRightWhitespace(char *thisline);
      char *RunCommand(const char *command);
      int PutDataIntoSecureRemoteFile(const char *dir, const char *file, const char *stringbuf, int stringlen);
      int CopyFile(const char *local_file, const char *remote_file);
      int DeleteThisKey(const char *oldkeyname);
      int AddThisKey(const char *newkeyname, RSAKeyPair *newpubkey);
      LIBSSH2_CHANNEL *GetSSHClientChannel();
   private:
      LIBSSH2_SESSION *tsession;
      LIBSSH2_CHANNEL *tchannel;
      const char *our_username;
      const char *our_keyname;
      RSAKeyPair *our_pubkey;
      RSAKeyPair *our_prvkey;
      const char *our_pass;
};

#endif
